package mdt.action;

import mdt.program.Displayer;
import mdt.program.GraphManager;
import mdt.appmodel.gen.ObjectFactory;
import mdt.appmodel.gen.RectType;
import mdt.figure.FigTextEditorMDT;
import mdt.utils.XmlFormatter;
import org.tigris.gef.base.Diagram;
import org.tigris.gef.base.Editor;
import org.tigris.gef.base.Globals;
import org.tigris.gef.presentation.Fig;
import org.tigris.gef.presentation.FigGroup;
import sun.awt.SunHints;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.LinkedList;
import java.util.List;

/**
 * Created by xiaobyu on 7/20/2016.
 */
public class SaveAsAction extends AbstractAction {

    private static final int margin = 50;

    public SaveAsAction() {
        super("Save As ...");
    }

    enum SaveType {
        MDT, JPG, PNG, SVG
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        try {
            Editor ce = Globals.curEditor();
            if (ce.getActiveTextEditor() != null) {
                ((FigTextEditorMDT)ce.getActiveTextEditor()).endEditing();
            }

            GraphManager.GraphInfo infoSet = null;
            if (e.getSource() instanceof GraphManager.GraphInfo) {
                infoSet = (GraphManager.GraphInfo)e.getSource();
            } else {
                infoSet = GraphManager.getActiveGraphInfo();
            }
            Diagram diagram = infoSet.diagram;
            File file;
            FileFilter mdtFilter = new FileFilter() {
                @Override
                public boolean accept(File f) {
                    if (f.isDirectory()) return true;
                    if (f.getName().toLowerCase().endsWith(".mdt")) return true;
                    return false;
                }

                @Override
                public String getDescription() {
                    return "MDT files(*.mdt)";
                }
            };

            FileFilter jpgFilter = new FileFilter() {
                @Override
                public boolean accept(File f) {
                    if (f.isDirectory()) return true;
                    if (f.getName().toLowerCase().endsWith(".jpg")) return true;
                    return false;
                }

                @Override
                public String getDescription() {
                    return "JPG pictures(*.jpg)";
                }
            };

            FileFilter pngFilter = new FileFilter() {
                @Override
                public boolean accept(File f) {
                    if (f.isDirectory()) return true;
                    if (f.getName().toLowerCase().endsWith(".png")) return true;
                    return false;
                }

                @Override
                public String getDescription() {
                    return "PNG pictures(*.png)";
                }
            };

            FileFilter svgFilter = new FileFilter() {
                @Override
                public boolean accept(File f) {
                    if (f.isDirectory()) return true;
                    if (f.getName().toLowerCase().endsWith(".svg")) return true;
                    return false;
                }

                @Override
                public String getDescription() {
                    return "SVG pictures(*.svg)";
                }
            };

            FileFilter allFilter = new FileFilter() {
                @Override
                public boolean accept(File f) {
                    if (f.isDirectory()) return true;
                    String lower = f.getName().toLowerCase();
                    if (lower.endsWith(".svg") || lower.endsWith(".jpg")
                            || lower.endsWith("mdt") || lower.endsWith("svg"))
                        return true;
                    return false;
                }

                @Override
                public String getDescription() {
                    return "All supported formats(*.mdt, *.jpg, *.png, *.svg)";
                }
            };


            SaveType type = SaveType.MDT;
            do {
                JFileChooser chooser = new JFileChooser(GraphManager.getLastVisitedDir());
                chooser.addChoosableFileFilter(mdtFilter);
                chooser.addChoosableFileFilter(jpgFilter);
                chooser.addChoosableFileFilter(pngFilter);
                chooser.addChoosableFileFilter(svgFilter);
                chooser.addChoosableFileFilter(allFilter);
                chooser.setDialogTitle("Save as...");
                int result = chooser.showSaveDialog(Displayer.instance().getJFrame());
                if (result != JFileChooser.APPROVE_OPTION) {
                    return;
                }

                file = chooser.getSelectedFile();
                String lowered = file.getName().toLowerCase();
                if (lowered.endsWith(".mdt")) {
                    type = SaveType.MDT;
                } else if (lowered.endsWith(".jpg")) {
                    type = SaveType.JPG;
                } else if (lowered.endsWith(".png")) {
                    type = SaveType.PNG;
                } else if (lowered.endsWith(".svg")) {
                    type = SaveType.SVG;
                } else {
                    if (chooser.getFileFilter() == jpgFilter) {
                        type = SaveType.JPG;
                    } else if (chooser.getFileFilter() == pngFilter) {
                        type = SaveType.PNG;
                    } else if (chooser.getFileFilter() == svgFilter) {
                        type = SaveType.SVG;
                    } else {
                        type = SaveType.MDT;
                    }
                }

                String ext = "." + type.name().toLowerCase();
                GraphManager.setLastVisitedDir(file.getParentFile().getAbsolutePath());
                if (!file.getName().toLowerCase().endsWith(ext)) {
                    file = new File(file.getParent() + File.separator + file.getName() + ext);
                }
                if (file.exists()) {
                    int res = JOptionPane.showConfirmDialog(Displayer.instance().getJFrame(),
                            "File " + file.getName() + " already exists, overwrite?",
                            "Overwrite?", JOptionPane.OK_CANCEL_OPTION);
                    if (res == JOptionPane.CANCEL_OPTION) {
                        continue;
                    }
                }
                break;
            } while (true);
            if (file != null) {

                List<Fig> figs = infoSet.editor.getFigs();
                Globals.showStatus("Writing " + file.getAbsolutePath() + "...");
                switch (type) {
                    case MDT:
                        FileOutputStream fos = new FileOutputStream(file);
                        ObjectOutput s = new ObjectOutputStream(fos);
                        diagram.preSave();
                        s.writeObject(diagram);
                        diagram.postSave();
                        Globals.showStatus("Wrote " + file.getAbsolutePath());
                        fos.close();

                        if (type == SaveType.MDT) {
                            infoSet.file = file;
                            infoSet.setDirty(false);
                            infoSet.setTitle(file.getName());
                        }
                        break;
                    case JPG:
                    case PNG:
                        diagram.preSave();

                        Rectangle bounds = null;
                        for (Fig f : figs) {
                            if (bounds == null) {
                                bounds =  f.getBounds();
                            } else {
                                bounds.add(f.getBounds());
                            }
                        }

                        if (bounds == null) {
                            bounds = new Rectangle(0, 0, margin * 2, margin * 2);
                        }
                        if (figs.size() > 0) {
                            bounds.width += margin * 2;
                            bounds.height += margin * 2;
                        }

                        BufferedImage image = new BufferedImage(bounds.width, bounds.height,
                                type ==SaveType.PNG ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
                        Graphics2D g = (Graphics2D) image.getGraphics();
                        //g.setComposite(AlphaComposite.Clear);
                        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, SunHints.VALUE_ANTIALIAS_ON);
                        g.setColor(Color.white);
                        g.fillRect(0, 0, image.getWidth(), image.getHeight());
                        if (figs.size() > 0) {
                            int xClip = margin - bounds.x;
                            int yClip = margin - bounds.y;
                            g.translate(xClip, yClip);
                            for (Fig f : figs) {
                                f.paint(g);
                            }
                        }
                        fos = new FileOutputStream(file);
                        ImageIO.write(image, type.name().toLowerCase().substring(1), fos);
                        fos.close();
                        diagram.postSave();
                        break;
                    case SVG:
                        StringBuffer sb = new StringBuffer("<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" " +
                                " width=\"1000\" height=\"1800\">");

                        sb.append("<defs>");
                        if (figs.size() > 0) {
                            LinkedList<Fig> ll = new LinkedList<>(figs);
                            while (ll.size() > 0) {
                                Fig f = ll.remove();

                                if (f instanceof FigGroup && !((FigGroup) f).isIntegrited()) {
                                    ll.addAll(0, ((FigGroup)f).getFigs());
                                }

                                if (!f.isFilled()) continue;

                                switch (f.getFillType()) {
                                    case LINEAR_GRADIENT:
                                    case LINEAR_REFLECT_GRADIENT:
                                        sb.append("<linearGradient id='" + f.getId() + "' x1='0%' y1='0%' x2='" +
                                                (f.getFillType() == Fig.FILL_TYPE.LINEAR_GRADIENT ? 100 : 50) + "%' y2='0%' spreadMethod='" +
                                                (f.getFillType() == Fig.FILL_TYPE.LINEAR_GRADIENT ? "pad" : "reflect") + "'>" +
                                                "<stop offset='0%' style='stop-color:" + getColorSVGStr(f.getGradientStart()) + ";stop-opacity:1' />" +
                                                "<stop offset='100%' style='stop-color:" + getColorSVGStr(f.getGradientEnd()) + ";stop-opacity:1' />" +
                                                " </linearGradient>");
                                        break;
                                    case RADIAL_GRADIENT:
                                        sb.append("<radialGradient id='" + f.getId() + "'>" +
                                                "<stop offset='0%' style='stop-color:" + getColorSVGStr(f.getGradientStart()) + ";stop-opacity:1' />" +
                                                "<stop offset='100%' style='stop-color:" + getColorSVGStr(f.getGradientEnd()) + ";stop-opacity:1' />" +
                                                "</radialGradient>");
                                        break;
                                }
                            }
                        }

                        sb.append("</defs>");
                        for (Fig f : figs) {
                            f.appendSvg(sb);
                        }
                        sb.append("</svg>");

                        String formatted = sb.toString();

                        try {
                            formatted = XmlFormatter.format(formatted);
                        }  catch (Exception e1) {
                            e1.printStackTrace();
                        }

                        fos = new FileOutputStream(file);
                        fos.write(formatted.getBytes());
                        fos.close();

                        ObjectFactory of = new ObjectFactory();
                        RectType rt = of.createRectType();


                        break;
                }
            }
        } catch (FileNotFoundException ignore) {
            System.out.println("got an FileNotFoundException");
        } catch (IOException ignore) {
            System.out.println("got an IOException");
            ignore.printStackTrace();
        }
    }

    private String getColorSVGStr(Color color) {
        return "rgb(" + color.getRed() + "," + color.getGreen() + "," + color.getBlue() + ")";
    }

}
